有了一個自動化的建置系統,下一步就是用他做簡單的持續整合啦。
仔細看了一下,phing其實提供了足夠的機制,讓我們透過phing以及一些schedule機制(cron等),就可以做基本的持續整合(CI, Continuous Integration)。
參考:
http://www.phing.info/
先說一下,如果真的要做CI,還是要一台伺服器比較好。
通常的CI過程:
為了節省時間,我略去了1跟2兩個步驟。不過phing是可以支援cvs、svn跟git的。而定時啟動,可以靠系統的schedule機制來達成,例如cron,這應該不困難。
先設計一下簡單的流程:
在使用前,還需要確定幾件事:
就先來看一下build.xml腳本:
<?xml version="1.0" encoding="UTF-8"?>
<project name="2-3a" default="dist">
<target name="dist" depends="build">
<zip destfile="dist/2-3a.zip">
<fileset dir="builds">
<include name="**/*.php" />
</fileset>
</zip>
</target>
<target name="build" depends="test">
<copy todir="builds">
<fileset dir="src">
<include name="**.php" />
</fileset>
</copy>
</target>
<target name="test" depends="clear">
<phpunit failureproperty="testresult">
<formatter todir="reports" type="xml" outfile="phpunit_report.xml" />
<batchtest>
<fileset dir="tests">
<include name="TestScormTimeUtils.php" />
</fileset>
</batchtest>
</phpunit>
</target>
<target name="clear">
<delete>
<fileset dir="builds">
<include name="**.*" />
</fileset>
</delete>
<delete>
<fileset dir="reports">
<include name="**.*" />
</fileset>
</delete>
<delete>
<fileset dir="dist">
<include name="**.*" />
</fileset>
</delete>
</target>
<target name="mailtest">
<mail tolist="fillano.feng@gmail.com" from="fillano2001@yahoo.com.tw" subject="mailtest">test mail body.</mail>
</target>
<target name="timestamp" depends="test">
<tstamp>
<format property="reporttime" pattern="%Y%m%d%H%M%S" />
</tstamp>
</target>
<target name="notify" depends="timestamp">
<if>
<equals arg1="${testresult}" arg2="true" />
<then>
<mail tolist="fillano.xxxx@gmail.com" from="fillanoxxxx@yahoo.com.tw" subject="build failed">build failed. please check reports for detail. http://localhost/tests/reports/${reporttime} ...</mail>
</then>
<else>
<mail tolist="fillano.xxxx@gmail.com" from="fillanoxxxx@yahoo.com.tw" subject="build passed">build passed. please check reports for detail. http://localhost/tests/reports/${reporttime} ...</mail>
</else>
</if>
</target>
<target name="reportdir" depends="notify">
<mkdir dir="/Users/fillano/Dropbox/Dev/www/html/reports/${reporttime}" />
</target>
<target name="htmlreport" depends="reportdir">
<phpunitreport infile="reports/phpunit_report.xml" format="frames" todir="/Users/fillano/Dropbox/Dev/www/html/reports/${reporttime}" styledir="vendor/phing/phing/etc" />
</target>
<target name="cibuild" depends="htmlreport">
<echo msg="build for CI" />
</target>
</project>
為了做CI,特別做了一個target叫做cibuild,然後透過depends把整個流程串起來。先執行一下看看:
Feng-Hsu-Pingteki-MacBook-Air:2-3a fillano$ ./phing cibuild
Buildfile: /Users/fillano/builds/ironman6/2-3a/build.xml
2-3a > clear:
[delete] Deleting 1 files from reports
2-3a > test:
2-3a > timestamp:
2-3a > notify:
[mail] Sending mail to fillano.feng@gmail.com
2-3a > reportdir:
[mkdir] Created dir: /Users/fillano/Dropbox/Dev/www/html/reports/20131018223544
2-3a > htmlreport:
2-3a > cibuild:
[echo] build for CI
BUILD FINISHED
Total time: 0.5631 seconds
然後到gmail看一下信:
打開信裡面的連結,可以看到測試報告:
再來修改一下測試,讓測試失敗看看:
<?php
require "vendor/autoload.php";
require "src/ScormTimeUtils.php";
class TestScormTimeUtils extends PHPUnit_Framework_TestCase
{
public $fixture1 = array("0000:20:21.023", "0002:23:20.324", "0002:43:41.347");
public $fixture2 = array('0000:00:23.043', 23043);
public function testScormTimeAdd() {
$this->assertEquals(ScormTimeUtils::SCORMTimeAdd($this->fixture1[0], $this->fixture1[1]), $this->fixture1[2]);
$this->assertEquals(ScormTimeUtils::SCORMTimeAdd('0000:00:00.000', '0000:00:00.000'), '0000:00:00.000');
}
public function testScormTimeDiff() {
$this->assertEquals(ScormTimeUtils::SCORMTimeDiff($this->fixture1[2], $this->fixture1[1]), $this->fixture1[0]);
}
public function testScormTimeParser() {
$this->assertEquals(ScormTimeUtils::SCORMTimeParser($this->fixture2[0]), $this->fixture2[1]);
}
/**
* @expectedException InvalidArgumentException
* @test
*/
public function doScormTimeParserSecException() {
ScormTimeUtils::SCORMTimeParser('0000:00:61.000');
}
/**
* @expectedException InvalidArgumentException
* @test
*/
public function doScormTimeParserMinException() {
ScormTimeUtils::SCORMTimeParser('0000:62:59.000');
}
public function testScormTimeFormat() {
$this->assertEquals(ScormTimeUtils::SCORMTimeFormat($this->fixture2[1]), $this->fixture2[0]);
$this->assertEquals(true, false);//this assert will fail...
}
}
然後再跑一次cibuild:
Feng-Hsu-Pingteki-MacBook-Air:2-3a fillano$ ./phing cibuild
Buildfile: /Users/fillano/builds/ironman6/2-3a/build.xml
2-3a > clear:
[delete] Deleting 1 files from reports
2-3a > test:
2-3a > timestamp:
2-3a > notify:
[mail] Sending mail to fillano.feng@gmail.com
2-3a > reportdir:
[mkdir] Created dir: /Users/fillano/Dropbox/Dev/www/html/reports/20131018230306
2-3a > htmlreport:
2-3a > cibuild:
[echo] build for CI
BUILD FINISHED
Total time: 0.8938 seconds
這次會收到建構失敗的通知:
然後看一下測試報告:
這樣就知道哪裡測試失敗。
除了每次的測試結果,透過上一層目錄,也可以看一下每次測試的結果:
=====
在多人協作的專案中,由於每個人只負責一部分,有時候因為一些依賴性的關係,要到每個人的開發結果都上到版本管理時才會發現。使用CI有一個好處,就是早期發現早期治療,這樣可以避免問題進一步擴大。
明天再來嘗試一下真正的CI伺服器方案看看。